![]() |
|
|||||
Interfaces: Rollen, die Objekte spielen können Ein Interface hat damit den Charakter einer Rolle, die ein reales Objekt beherrscht oder nicht. Somit sind Interfaces abstrakt, man kann von ihnen keine Objekte erzeugen. Eine Klasse kann beliebig viele Interfaces implementieren. Jedes Objekt kann dann z.B. beim Methoden-Aufruf anstelle eines Interface-Parameters stehen, sofern die zugehörige Klasse das Interface implementiert hat. Damit werden schwerwiegende Defizite der Vererbung unter Beibehaltung der Hauptvorteile wie Substitution behoben. Methoden und DatenKeine globalen Funktionen und Daten Für C/C++-Konvertiten ist die Tatsache ungewohnt, dass es keine globalen Funktionen und Daten außerhalb von Klassen gibt. Der auszuführende Code ist immer in den Methoden (Methods) der Klassen enthalten. Aufruf oder Zugriff mit Hilfe des Da Methoden und Daten an Klassen oder deren Objekte gebunden sind, erfolgt der Aufruf einer Klassen-/Objekt-Methode oder der Zugriff auf Daten von außen über den zugehörigen Klassen- bzw. Objektnamen, separiert durch den Punkt (dot-operator)7 vom Methoden-/Datennamen: Klasse.methode() bzw. objekt.methode() Klasse.feld bzw. objekt.feld Die Klammern müssen bei Methoden immer angegeben werden, auch wenn sie keine Parameter haben. Damit ist ein Methoden-Aufruf leicht von einem Datenzugriff zu unterscheiden. ArraysWie bei C/C++ werden Arrays als geordnete Kollektion von Elementen mit gleichem Typ durch eckige Klammern deklariert, wobei auch der Zugriff auf ein Element über den Index in eckigen Klammern erfolgt. Damit sind allerdings die Gemeinsamkeiten mit C/C++ auch schon erschöpft. Denn bereits die bevorzugte Art, in Java Arrays zu deklarieren, stellt sich folgendermaßen dar:
byte[] bArr; String[] sArr; Da die Angabe der Größe bei der Deklaration nicht erlaubt ist, kann die Array-Variable ein Array beliebiger Länge referenzieren. Diese Art der Deklaration kann auch für die Rückgabe von Arrays aus einer Methode verwendet werden (was C/C++ ohnehin nicht erlaubt). Anlage eines Arrays mittels new Mit der o.a. Deklaration ist noch kein Array angelegt. Dies geschieht normalerweise mittels eines new-Ausdrucks und kann direkt bei der Deklaration oder auch zu einem späteren Zeitpunkt erfolgen: byte[] bArr= new byte[10]; Die Variable bArr referenziert nun ein Array mit zehn Elementen vom Typ byte (Näheres zu byte: siehe 1.3). Für kleine Arrays gibt es eine sehr praktische Kurzform, die neben der (impliziten) Anlage des Arrays bereits den einzelnen Array-Elementen Werte zuweist: int[] iArr= {1,2,3}; int[] iArr= new int[3]; iArr[0]=1; iArr[1]=2; iArr[2]=3; 1.1.2 Java-Applikation
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Modularisierung des Codes mit Hilfe des Package-Konzepts |
| Ein hierarchisches Namenssystem, das es ermöglicht, Namenskollisionen global zu vermeiden |
Die Konvention beinhaltet eine Anleitung zur Abbildung der Package- und Klassennamen in die Verzeichnisstrukturen und Dateien unterschiedlicher Betriebssysteme. Damit müssen natürlich die Namen von Packages gültige Verzeichnisnamen bei allen Betriebssystemen sein.
Package: Kollektion zusammengehöriger Klassen/Interfaces
Nach dem Vorbild von Modula werden alle Klassen in Java-Packages gekapselt. Ein Package besteht aus einer Kollektion von:
| Klassen |
| Interfaces (Schnittstellen) |
| Subpackages |
Mindestens besteht es aus einem dieser Elemente. Ein Package kann also durchaus nur eine »Hülle« für Subpackages sein, d.h. selbst keine Klassen oder Interfaces enthalten.
Ein Package bildet für die enthaltenen Mitglieder einen so genannten Namensraum (namespace).
Innerhalb des Namensraums müssen die Namen der Mitglieder eindeutig sein, außerhalb können sie immer über den vorangestellten Package-Namen identifiziert werden.
Damit wird das Problem der Eindeutigkeit auf die Stufe der Packages verlagert, d.h., für eine Internet-Anwendung muss beispielsweise gewährleistet sein, dass Package-Namen eindeutig sind.
Konvention für eindeutige Package-Namen
Sun hat sich für die Packages aus dem eigenen Haus die Namen beginnend mit java, javax oder sun reserviert.
Der Rest der Welt generiert eindeutige Bezeichnungen anhand der eigenen global eindeutigen Internet-Domain-Namen. Nach Java-Konvention kehrt man sie dazu um und schreibt alles durchgängig klein, also z.B.:
| Domain Name | Package-Name startet mit |
Spezieller Package-Name |
| MeinName.de | de.meinname | de.meinname.meinpaket |
| OurCompany.com | com.ourcompany | com.ourcompany.project1.dbms |
| IBM.com | com.ibm | com.ibm.sf.samples.addressbook |
Hierarchie mittels Subpackages
Die letzten beiden Beispiele zeigen hierarchisch angeordnete Packages, wobei ein Subpackage-Name vom übergeordneten Package-Namen durch einen Punkt getrennt wird.
Alle Package-Namen des SanFrancisco Business-Projekts von IBM beginnen z.B. mit com.ibm.sf, wobei Beispiele in einer Gruppe von Subpackages enthalten sind, die mit com.ibm.sf.samples beginnen.
simple vs. fully qualified name
Innerhalb eines Packages müssen die so genannten einfachen Namen (simple names) von Subpackages, Klassen und Interfaces eindeutig sein. Es können also keine zwei Mitglieder eines Packages den gleichen Namen tragen.
Beim vollen Namen (fully qualified name) wird der einfache Name um den vorangestellten vollen Package-Namen ergänzt.
Innerhalb des Subpackages java.awt gibt es z.B. ein Subpackage mit einfachem Namen image bzw. vollem Namen java.awt.image.
Damit ist u.a. ausgeschlossen, dass in java.awt ein weiteres Mitglied, z.B. eine Klasse mit Namen image existiert, wobei allerdings eine Klasse Image erlaubt ist, da Java zwischen Groß- und Kleinbuchstaben unterscheidet.
No-Name/unnamed/Default-Package
Obwohl »gute Sitte«, muss ein Package-Name nicht unbedingt angegeben werden. Fehlt die Angabe, so gehören alle angegebenen Klassen bzw. Interfaces zum default bzw. unnamed Package.
| Da weder die Anzahl der unnamed-Packages noch ihre Abbildung in ein reales Dateisystem festgelegt ist, sollten nur kleine Beispiele bzw. temporärer Code in einem default Package getestet werden. |
Für rein lokale Anwendungen kann die erwähnte Namenskonvention sicherlich ignoriert werden, für kommerzielle Anwendungen ist sie sehr hilfreich.10
Java-Code - genauer eine Übersetzungseinheit (Compilation-Unit) - besteht aus folgenden drei Elementen, die exakt in dieser Reihenfolge aufeinander folgen müssen:
Definieren und Importieren von Packages
| einer Package-Deklaration (optional) |
| Import-Anweisungen von anderen Packages (optional) |
| Klassen bzw. Interface-Definitionen (mindestens eine) |
Im folgenden Beispiel wird zuerst ein Package deklariert, gefolgt von zwei Importanweisungen (Erklärung siehe 1.2.3) und einer Klasse:
package com.company.samples.test; import java.awt.*; import java.math.BigInteger;
// Anschließend Klassen und Interfaces class Test1 { ... }
Durch das vorangestellte Schlüsselwort package wird das Package deklariert. Fehlt die Zeile, handelt es sich um das unnamed Package.
Klassen und Interfaces (nicht Subpackages!) im selben Package können sich gegenseitig über den einfachen Namen referenzieren. Darüber hinaus kann auch auf die fundamentalen Klassen und Interfaces von java.lang immer über den einfachen Namen zugegriffen werden.11
Um auf Klassen und Interfaces in anderen Packages zugreifen zu können, müssen diese dort public erklärt sein:
public class Test1 { ... }
Für den Zugriff auf public erklärte Klassen anderer Packages muss per Default der volle Name verwendet werden.
Import: Vereinfachter Zugriff auf Klassen anderer Packages
Da dies auf Dauer mühselig ist, kann mittels der Importanweisungen auf alle (oder nur eine) Klasse(n) bzw. Interface(s) des angegebenen Packages auch über den einfachen Namen zugegriffen werden.
Im Beispiel von 1.2.2 werden mit Hilfe des Schlüsselwortes import und des Metasymbols * 12 alle Klassen und Interfaces aus java.awt importiert, gefolgt vom Import genau einer Klasse BigInteger aus java.math.
Führt der Import allerdings zu Namenskollisionen, da in zwei Packages die einfachen Namen gleich sind, muss der Konflikt durch Angabe des vollen Namens beseitigt werden.13
Die Abbildung des Package-Konzepts in ein Verzeichnis- und Dateisystem ist natürlich vom Betriebssystem abhängig. In Java gibt es hierzu die folgenden Regeln, die aber nicht unmittelbar zum Sprachkern zählen und somit durchaus Ausnahmen zulassen:
Regeln zu Packages,
compilation unit, Klassen und Dateisystem
| 1. | Eine Übersetzungseinheit kann beliebig viele Klassen und Interfaces enthalten, wovon jedoch höchstens eine public erklärt werden kann. |
| 2. | Eine Übersetzungseinheit wird in einer Datei mit der Extension .java abgespeichert. |
| 3. | Der Name der Datei muss den Namen der Klasse bzw. des Interfaces haben, die public erklärt wird. Gibt es keine, kann der Name frei gewählt werden. |
| 4. | Nach dem Kompilieren der Übersetzungseinheit wird der Byte-Code jeder Klasse bzw. jedes Interfaces in eine separate Datei mit Namen der Klasse bzw. des Interfaces und der Extension .class abgespeichert. |
| 5. | Die Package-Hierarchie wird in eine entsprechende Verzeichnishierarchie aufgelöst, d.h., die .java- bzw. .class-Dateien befinden sich in Unterverzeichnissen, die den Package-Namen abbilden.14 |
Nur die vierte Regel muss von allen Java-Entwicklungsumgebungen eingehalten werden. Die anderen gelten für Entwicklungsumgebungen, die dateibasierend sind und zur Speicherung des Programmcodes keine Datenbank verwenden.15
Entsprechend der fünften Regel liegt im Beispiel 1.2.2 die Datei Test1.class des Packages com.company.samples.test bei Windows im Unterverzeichnis com\company\samples\test bzw. bei Unix im Unterverzeichnis com/company/samples/test.
Diese Regel besagt nicht, dass die .java-Dateien im selben Verzeichnis wie die zugehörigen .class-Dateien liegen müssen. Denn die Unterverzeichnisse können für .java- und .class-Dateien verschiedene Ausgangsverzeichnisse (Root-Verzeichnisse) haben. 16
Wäre die Klasse Test1 public erklärt, müsste die Übersetzungseinheit, die den Java-Code enthält, nach der dritten Regel in einer Datei Test1.java abgespeichert sein.
Dem Java-Interpreter, z.B. java, braucht nicht angegeben zu werden, wo sich die Klassen der Plattform (J2SE) bzw. der Extentions befinden.
Für alle anderen Klassen, die zur Applikation gehören, sind folgende Regeln zu beachten. Der Interpreter sucht
Regeln zur
Ausführung von Applikationen
| 1. | per default innerhalb des aktuellen Verzeichnisses die Klassen des unnamed Packages. |
| 2. | per default unterhalb des aktuellen Verzeichnisses in einem Unterverzeichnis, das dem Package-Namen entspricht, nach den Klassen des Packages. |
| 3. | unterhalb der Verzeichnisse, die entweder mittels der Umgebungsvariable CLASSPATH (des Betriebssystems) oder alternativ der Option -classpath (des Interpreters) gesetzt werden. |
Die flexibelste Methode ist wohl, mittels -classpath beim Aufruf die Unterverzeichnisse anzugeben. Die Angaben in CLASSPATH werden damit überschrieben bzw. ersetzt.
Aufruf einer
Applikation unter Windows
Werden z.B. nur Klassen aus dem Package j2buch.kap1 benötigt, wobei die Klasse j2buch.kap1.Test1 ausgeführt werden soll, dann kann die Klasse Test1 nach der zweiten Regel mittels
C:\JB\classes> java j2buch.kap1.Test1
aufgerufen werden. Dies setzt voraus, dass sich Test1 im Unterverzeichnis C:\JB\classes\j2buch\kap1 befindet.
Nach der dritten Regel kann Test1 auch mittels
java -classpath C:\JB\classes j2buch.kap1.Test1
aus jedem beliebigen Verzeichnis aufgerufen werden.
Eine weitere Möglichkeit ist die, alle benötigten Klassen in eine JAR-Datei test.jar zu packen, die Test1 als Main-Class-Attribut enthält, und diese mittels der Option -jar auszuführen, z.B.:
java -jar C:\JB\test.jar
Abbruch der normalen Programmausführung durch Exceptions
Fehler, die nicht durch den Compiler abgefangen werden können, d.h. erst bei der Ausführung in der JVM auftreten, werden durch »Auslösen einer Ausnahme« (throwing an exception) von der JVM signalisiert.
Diese Ausnahme kann dann entweder im Programm durch einen entsprechenden Exception-Handler behandelt, d.h. abgefangen werden, oder die JVM bricht die Programmausführung mit einer detaillierten Fehlermeldung (Art/Ort der Exception) ab.
Acht so genannte primitive Datentypen sind Bestandteil der Sprache, werden also vom Compiler direkt erkannt. Hierzu zählen ein logischer (boolean) Typ, ein Zeichentyp sowie sechs numerische Typen.
Daneben gibt es noch Referenz-, Klassen- und Array-Typen.
Zeichen und ganze Zahlen werden unter dem Begriff integraler Typ, float und double unter Floating-point-Typ zusammengefasst.
Die primitiven Datentypen sind in der nachfolgenden Tabelle kurz zusammengestellt:
| Type | Wertebereich | Default-Wert | Bit-Größe | Anmerkung |
| boolean | true, false | false | 1 | |
| char | \u0000 .. \uFFFF | \u0000 | 16 | unsigned |
| byte | -27 .. 27 -1 | 0 | 8 | |
| short | -215 .. 215 -1 | 0 | 16 | |
| int | -231 .. 231 -1 | 0 | 32 | |
| long | -263 .. 263 -1 | 0 | 64 | |
| float | Float.MIN_VALUE .. Float.MAX_VALUE, Float.NaN, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY |
0.0 | 32 | Darstellbare Werte: ±1.402e-45 .. ±3.402e38 |
| double | Double.MIN_VALUE .. Double.MAX_VALUE, Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY |
0.0 | 64 | Darstellbare Werte: ±4.94e-324 .. ±1.79e308 |
Gegenüber C/C++ gibt es einen eigenen boolean-Typ, der eine Umwandlung von/nach Integer nicht zulässt, d.h., 0 oder 1 werden als Ersatz für false und true nicht akzeptiert (siehe 1.5).
Alle numerischen Typen sind signed, d.h. erlauben Vorzeichen und haben eine fest definierte Größe, unabhängig von der Maschine bzw. dem Betriebssystem.
Nachfolgend die wichtigsten Regeln zu Zahlen-Operationen:
Over- bzw. Underflow bei Integer-Werten
| 1. | Bei Integer-Arithmetik stellt weder der Compiler noch die JVM sicher, dass der Wertebereich ausreicht. Ist das Ergebnis außerhalb des Wertebereichs, ist es schlichtweg falsch. |
| 2. | Nur eine Division durch Null bzw. Modulo Null erzeugt eine ArithmeticException (Ausnahme siehe 1.2.5). |
Wertüberschreitung bei Floating-Point-Typen
| 3. | Floating-Point-Typen kennen die Werte »nicht definiert«, d.h. NaN (Not-a-Number) sowie ±Unendlich, d.h. NEGATIVE_INFINITY bzw. POSITIVE_INFINITY, die Überschreitungen des Wertebereichs abfangen. |
| 4. | Eine Operation mit einem »nicht definierten« Wert ergibt kein Ergebnis im normalen Wertebereich. |
| 5. | Eine Operation mit NaN führt immer zum Ergebnis NaN. |
| Berechnung von | Ergebnis | Anmerkung |
| -0.0 / 0.0 | NaN | Undefiniert, d.h. NaN |
| 1.0 / -0.0 | NEGATIVE_INFINITY | es gibt eine negative Null |
| (0.0 / 0.0) * (1.0 / 0.0) | NaN | NaN bleibt immer bestehen |
| 0.0 == -0.0 | true | -0.0 ist gleich 0.0 17 |
| -0.0/0.0 == -0.0/0.0 | false | NaN ist mit nichts gleich18 |
Aufbauend auf einem für Java erlaubten Zeichensatz - dem Unicode - besteht Java-Source-Code aus folgenden atomaren Elementen:
Bestandteile eines
Java-Programms
| Whitespaces (Zwischenräume) |
| Comments (Kommentare) |
| Identifier (Bezeichner bzw. Namen) |
| Separators (Trennzeichen) |
| Literals (Literale) |
| Keywords (Schlüsselworte) |
| Operators (Operatoren) |
Java verwendet als erlaubten Zeichensatz Unicode, womit es sich bereits von C/C++ in seinen Grundlagen unterscheidet.
Eine Sprache für Internet-Applikationen muss neben dem Standardzeichensatz für Englisch auch andere Zeichensätze wie Arabisch, Katakana, Griechisch etc. darstellen können.
Da Unicode-Zeichen 16-Bit codiert sind, können prinzipiell 65.536 (=216 ) Zeichen dargestellt werden. Die Unicode-Tabelle ist in Bereiche für verschiedene Sprachen eingeteilt.
Kompatibel zu
ASCII, ISO-Latin-1
Im Tabellenbereich von 0...127 bzw. 0...255 ist Unicode identisch mit dem ASCII- bzw. ISO-Latin-1-Zeichensatz. Für diese Zeichen kann man also das oberste der beiden Bytes ignorieren.19
Da man selten eine Tastatur mit 65.536 Tasten zur Eingabe benutzt, gibt es eine spezielle Escape-Sequenz für Unicode-Zeichen (siehe 1.4.6).
Java ist frei formatierbar
(free-form)
Die Anzahl Leerstellen, Tabulatoren oder Zeilenumbrüche (Linefeed bzw. Carriage-Return) zwischen Token (Symbolen) können beliebig gewählt werden, sie werden ohnehin bei der lexikalischen Analyse durch den Compiler entsorgt.
Es gibt drei Arten von Kommentaren, die von C++ adaptiert wurden:
| einzeilige: |
i=i+1; // oder i++; oder ++i; oder i+=1;
| mehrzeilige: |
/* Arrays können im C/C++ oder im Java-Stil deklariert werden */ int iarr[]; byte[] barr;
| mehrzeilige Kommentare, die mit /** starten. Hieraus kann mit Hilfe von javadoc eine HTML-Dokumentation generiert werden. javadoc versteht einfache HTML-Formatierungen sowie mit @ beginnende Tags, d.h. Hinweise auf Text mit festgelegter Bedeutung: |
/** money factory class - a Pattern @author BG @version 0.9 <U>code name</U>: <B>W98 Green Banana</B> */
Ein Identifier ist ein vom Programmierer wählbarer Name für Variablen, Marken, Methoden und Klassen mit folgenden Restriktionen:
| Das erste Zeichen muss ein (Unicode) Buchstabe, ein Unterstreichungsstrich _ oder ein Währungssymbol $, £ bzw. ¥ sein. |
| Ab dem zweiten Zeichen sind noch zusätzlich Ziffern erlaubt. |
| Schlüsselwörter (siehe Tabelle 1.5) sind nicht erlaubt. |
Nachfolgend einige zulässige (erste Zeile) bzw. unzulässige Identifier:
_i__ £4 äß _123 Õre
2i ab/1 B-1 ab! a%b #a goto
Java verwendet neun Zeichen als Trennzeichen mit besonderer Bedeutung, wobei der häufigste Separator wohl das Semikolon ist, das Anweisungen abschließt. Die restlichen sind verschiedene Arten von Klammern, Komma und Punkt:
; , . ( ) { } [ ]
Im Gegensatz zu einem Identifier repräsentiert ein Literal einen konstanten Wert eines bestimmten Typs. Literale können in Ausdrücken, Zuweisungen und als Argumente beim Methoden-Aufruf verwendet werden.
Es gibt Literale zu den primitiven Typen, zur Klasse String, das null-Literal sowie noch Literale der Klasse Class, die im Folgenden kurz vorgestellt werden:
Die einzigen Literale vom Typ boolean sind true und false.
boolean ok = false;
Zeichen-Literale müssen immer in Hochkommata eingeschlossen werden.
Hexadezimale Eingabe von Zeichen
Für Zeichen, die nicht mittels Tastatur eingegeben werden können, wird die Unicode-Tabellenposition in Form von (maximal) vier hexadezimalen Ziffern 0..F (Basis 16) mit dem Präfix \u eingegeben.20 0 Die Hex-Ziffern können groß A..F oder klein a..f geschrieben werden.
Für die Eingabe von speziellen Zeichen gibt es in Java wie C/C++ die nachfolgenden Escape-Codes:
| Escape-Code | Zeichen |
'\'' |
Hochkomma (single quote) |
'\"' |
Anführungszeichen (double quote) |
'\\' |
Schrägstrich nach hinten (backslash) |
'\b' |
Schritt zurück (backspace) |
'\t' |
Tabulator (tab) |
'\n' |
Zeilenschaltung (linefeed/newline) |
'\r' |
Wagenrücklauf ( carriage return) |
'\f' |
Seitenschaltung (form feed) |
Mit Hilfe des Escape-Codes lassen sich Unicode-Zeichen eingeben:
char c1='\u00c4'; System.out.print(c1=='Ä'); // :: true
Die als integrale Literale bezeichneten ganzen Zahlen vom Typ int oder long können dezimal, hexadezimal oder sogar oktal eingegeben werden, wobei die hexadezimale Eingabe mit 0x oder 0X und die oktale mit 0 beginnen muss.
Alle Literale sind per default vom Typ int. Wird an das Literal (das Suffix) l oder L angehängt, ist es vom Typ long.
int i= 0x10+10+010; // 16+10+8 System.out.print(i+" "+0x10L); // :: 34 16
Ein Floating-Point-Literal vom Typ float oder double ist eine Zahl mit Dezimalpunkt und/oder einem angehängten Exponent und/oder einem Suffix f oder F für float bzw. d oder D für double. Fehlt das Suffix, ist das Literal per default vom Typ double.
Der Exponent beginnt mit E oder e, gefolgt von einem optionalen Vorzeichen und dem Exponenten (möglicher Wertebereich siehe Tabelle 1.2). Damit sind alle nachfolgenden Zahlen gültige Floating-Point-Literale:
0. .0 +1f -6e+1 7.1E-1F
Dabei ist die letzte Zahl gleich 0.71 und vom Typ float .
Strings sind Zeichensequenzen und werden immer in Anführungszeichen (double quotes) gesetzt. Innerhalb des Strings können die einzelnen Unicode-Zeichen (wie bei Zeichen-Literalen) per Escape-Code oder hexadezimal eingegeben werden.
System.out.print("\"\u00c4\tÖ\tÜ\"\nNeue Zeile");
gibt (unter Windows) zwei Zeilen auf der Konsole aus:21
"Ä Ö Ü" Neue Zeile
String-Literale sind keine Werte vom primitiven Typ, sondern sind eine kurze elegante Art, Objekte der Klasse String anzulegen.
Somit können auf String-Literale alle Instanz-Methoden der Klasse String angewendet werden, wie z.B. die Methode length(), die die Länge des Strings zurückgibt:
System.out.print("".length()); // :: 0
null: Kein Objekt referenziert
Neben den Variablen vom primitiven Typ gibt es noch Referenzvariablen, die auf Objekte von Klassen zeigen. Um anzuzeigen, dass eine Referenzvariable auf kein Objekt zeigt, wird das Literal null (ein Schlüsselwort) verwendet.
String s= null; // s zeigt auf kein String-Objekt
System.out.println(s); // :: null System.out.println(s.length()); // Exception
Die letzte Code-Zeile führt nicht zu einem Compilerfehler, sondern bei Ablauf des Programms zu einer NullPointerException, da von einem nicht existierenden Objekt keine Länge abgefragt werden kann.
Class-Literale
enthalten Klassen-Informationen
Die Klasse Class enthält Objekte zu allen Datentypen (inkl. sich selbst). Durch Anhängen von .class hinter einem beliebigen Typ kann man ein zu diesem Typ zugehöriges Literal vom Typ Class schaffen.
Class intTyp= int.class;
Dies kann u.a. zur Untersuchung von Klassen verwendet werden. Das nachfolgende Code-Fragment gibt alle Methoden der Klasse String aus (die Klasse Method ist aus Package java.lang.reflect zu importieren):
Class stringType= String.class;
Method[] methodArr= stringType.getMethods();
for (int i=0; i<methodArr.length; i++) System.out.println(methodArr[i]);
Keyword:
Identifier mit fester Bedeutung
Schlüsselwörter sind vordefinierte Identifier mit einer speziellen Bedeutung. Sie dürfen deshalb auch nicht als normale Identifier verwendet werden.
Es gibt zurzeit 59 Schlüsselwörter, die anhand ihrer Funktion in Kategorien eingeteilt werden können. Zum Beispiel gibt es für Bedingungen die Schlüsselworte if, else und switch und eine Gruppe von elf Schlüsselwörtern, die zwar reserviert (®) sind, aber nicht benutzt werden.
| abstract | const ® | float | int | protected | throw |
| boolean | continue | for | interface | public | throws |
| break | default | future ® | long | rest ® | transient |
| byte | do | generic ® | native | return | true |
| byvalue ® | double | goto ® | new | short | try |
| case | else | if | null | static | var ® |
| cast ® | extends | implements | operator ® | super | void |
| catch | false | import | outer ® | switch | volatile |
| char | final | inner ® | package | synchronized | while |
| class | finally | instanceof | private | this |
Operatoren sind spezielle Symbole für Operationen auf Operanden. Je nach Anzahl der Operanden, auf die der Operator angewendet wird, unterscheidet man unäre und binäre Operatoren sowie einen ternären Operator.
Java kennt 37 Operatoren, die anhand ihrer Funktion klassifiziert werden, wie z.B. arithmetische oder logische Operatoren. Operatoren werden in Kapitel 2 behandelt.